home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / waisgate / sersrch.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  16KB  |  599 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.    
  4.    Brewster@think.com
  5. */
  6.  
  7.  
  8. /* implements the search part of irext.h 
  9.    (search_word and finished_search_word)
  10.    -brewster
  11.  
  12. Split from irsearch.c
  13.  
  14.    5/31/91 Added scale_scores.  Fixed document_score_array to long.
  15.    7/8/91 Removed scale_scores, handled in search_word with doc_id > 0.
  16.    2/4/92 Made document_score_array a double.
  17.  
  18.    - Jonny G
  19.  * $Log:    sersrch.c,v $
  20.  * Revision 1.24  92/04/28  16:56:54  morris
  21.  * added boolean to serial engine
  22.  * 
  23.  * Revision 1.23  92/03/15  10:15:18  jonathan
  24.  * Added Simon Spero's ASSIGN replacement for read_bytes.
  25.  * 
  26.  * Revision 1.22  92/03/05  07:09:54  shen
  27.  * add two more dummy arguments to call to init_search_engine
  28.  * 
  29.  * Revision 1.21  92/02/12  17:29:52  jonathan
  30.  * Conditionalized inclusion of object code.
  31.  * 
  32.  * Revision 1.20  92/02/12  13:40:06  jonathan
  33.  * Added "$Log" so RCS will put the log message in the header
  34.  * 
  35. */
  36.  
  37. #include "cdialect.h"
  38. #include "irfiles.h"
  39. #include "irsearch.h"
  40. #include "irext.h"
  41. #include "byte_order.h"
  42. #include <string.h>
  43.  
  44. #ifdef BOOL
  45. #include "obj.h"
  46. #include "irparse.h"
  47. object* currentQuery = NULL; /* kludge until irext goes away */
  48. #endif /* def BOOL */
  49.  
  50. /* weighting for relevant document terms - 
  51.    this may become a parameter to the query.
  52. */
  53.  
  54. #define RF_WEIGHTING 0.1
  55.  
  56. /* ==================================
  57.  * ===  Initialization Functions  ===
  58.  * ==================================*/
  59.  
  60.  
  61. long init_search_engine(file, initialize, for_search, cm_mem_percent, 
  62. text_size, grow_percent)
  63.   char* file;
  64.   boolean initialize;
  65.   boolean for_search;
  66.   long cm_mem_percent;  /* unused */
  67.   long text_size;     /* unused */
  68.   long grow_percent;  /* unused */
  69. {
  70.   static boolean inited = false;
  71.  
  72.   if (inited == false)
  73.    { 
  74. #ifdef BOOL
  75.      initObj();
  76.      initBool();
  77. #endif
  78.      inited = true;
  79.    }
  80.  
  81.   return(0);
  82. }
  83.  
  84. long finished_search_engine()
  85. {
  86.   return(0);
  87. }
  88.  
  89.  
  90. /*
  91.  *  ext_open_database: see irext.h
  92.  */
  93.  
  94. long ext_open_database (db, initialize, for_search)
  95.      database *db;
  96.      boolean initialize;
  97.      boolean for_search;
  98. { /* this has to deal with the .inv file */
  99.   char file[MAX_FILE_NAME_LEN];
  100.  
  101.   if(initialize) /* make a new one */
  102.     db->index_stream = s_fopen(index_filename(file, db), "w+b");
  103.   else if(for_search) /* just search */
  104.     db->index_stream = s_fopen(index_filename(file, db), "rb");
  105.   else /* write to an existing db */
  106.     db->index_stream = s_fopen(index_filename(file, db), "r+b");
  107.  
  108.   if (db->index_stream == NULL) {
  109.     waislog(WLOG_HIGH, WLOG_ERROR,"2can't open the inverted index file %s\n", 
  110.         file);
  111.       disposeDatabase(db);
  112.       return(1);
  113.     }
  114.   return(0);
  115. }
  116.   
  117.  
  118.  
  119. /*
  120.  *  ext_close_database: see irext.h
  121.  */
  122.  
  123. long ext_close_database (db)
  124.      database *db;
  125. {
  126.   return(0);
  127. }
  128.  
  129. char *database_file(database_name)
  130.      char *database_name;
  131. {
  132.   return(database_name);
  133. }
  134.   
  135. /*===========================*
  136.  *===  Setting Paramters  ===*
  137.  *===========================*/
  138.  
  139. long max_hit_retrieved = 0;
  140. char **srcs = NULL;
  141.  
  142. long set_query_parameter (mask, parameters)
  143.      long mask;
  144.      query_parameter_type * parameters;
  145. {
  146.   switch (mask)
  147.     {
  148.     case SET_MAX_RETRIEVED_MASK:
  149.       max_hit_retrieved = parameters->max_hit_retrieved;
  150.       return(0);
  151.       break;
  152.     case SET_SELECT_SOURCE:
  153.       if(NULL != srcs){
  154.     if(NULL != srcs[0])
  155.       s_free(srcs[0]);
  156.     s_free(srcs);
  157.       }
  158.       srcs = parameters->srcs;
  159.       break;
  160.     default:
  161.       return(-1);
  162.       break;
  163.     }
  164.   return(0);
  165. }
  166.  
  167. /*==============================*
  168.  *===  Document Score Array  ===*
  169.  *==============================*/
  170.  
  171. double *document_score_array = NULL;
  172. long document_score_array_len = 0;
  173.  
  174. /* make_document_score_array insures that the document_score_array
  175.    array is long enough, if not it makes it long enough */
  176. static void make_document_score_array _AP((long length));
  177. static void make_document_score_array(length)
  178. long length;
  179. {
  180.   if(length <= document_score_array_len)
  181.     return;
  182.   /* we have to make a new one.  free the old one first (if any) */
  183.   if(document_score_array != 0){
  184.     s_free(document_score_array);
  185.   }
  186.   document_score_array = (double*)s_malloc(
  187.                      (size_t)(length * sizeof(double)));
  188.   document_score_array_len = length;
  189. }
  190.  
  191. static void destroy_document_score_array _AP((void));
  192. static void destroy_document_score_array()
  193. {
  194.   s_free(document_score_array);
  195.   document_score_array_len = 0;
  196. }
  197.     
  198. void clear_document_score_array()
  199. /* side effects the document_score_array. */
  200.   memset(document_score_array, 0, 
  201.      document_score_array_len * sizeof(double));
  202. }
  203.  
  204. /* for debugging purposes */
  205. void print_document_score_array(start,stop)
  206. unsigned long start;
  207. unsigned long stop;
  208. /* assumes start >= 0, stop < db->doc_table_allocated_entries */
  209. {
  210.     long i;
  211.     for(i = start; i <= stop; i++){
  212.         printf("entry number %d: %f \n", 
  213.                i, document_score_array[i]);
  214.     }
  215. }
  216.  
  217.  
  218.  
  219. /*=========================*
  220.  *===  Best Hits Array  ===*
  221.  *=========================*/
  222.  
  223. hit *best_hits_array = NULL;
  224. long best_hits_array_len = 0;
  225. long current_best_hit = 0;
  226.  
  227. /* see irext.h for doc */
  228. long init_best_hit (db)
  229.      database *db;
  230. {
  231.  
  232. #ifdef BOOL
  233.   if (currentQuery != NULL)
  234.     send(currentQuery,InitBestHit,db);
  235. #endif /* def BOOL */
  236.  
  237.   return(0);
  238. }
  239.  
  240. /* make_best_hits_array insures that the best_hits_array
  241.    array is long enough, if not it makes it long enough */
  242. static void make_best_hits_array _AP((long length));
  243. static void make_best_hits_array(length)
  244. long length;
  245. {
  246.   if(length <= best_hits_array_len)
  247.     return;
  248.   /* we have to make a new one.  free the old one first (if any) */
  249.   if(best_hits_array != 0){
  250.     s_free(best_hits_array);
  251.   }
  252.   best_hits_array = (hit*)s_malloc((size_t)(length * sizeof(hit)));
  253.   best_hits_array_len = length;
  254. }
  255.  
  256. static void destroy_best_hits_array _AP((void));
  257. static void destroy_best_hits_array()
  258. {
  259.   s_free(best_hits_array);
  260.   best_hits_array_len = 0;
  261. }
  262.     
  263. void clear_best_hits_array()
  264. /* side effects the best_hits_array.  XXX could use memset */
  265.   memset((char*)best_hits_array, 0, best_hits_array_len * sizeof(hit));
  266. }
  267.  
  268. /* for debugging purposes */
  269. void print_best_hits()
  270. {
  271.   long i;
  272.   for( i = 0; i < best_hits_array_len; i++){
  273.     if (best_hits_array[i].weight != 0)
  274.       { printf("Best hit %ld: weight %ld, doc_id %ld, headline %s, filename %s, lines %ld\n", 
  275.            i, best_hits_array[i].weight, 
  276.            best_hits_array[i].document_id,
  277.            best_hits_array[i].headline,
  278.            best_hits_array[i].filename,
  279.            best_hits_array[i].number_of_lines);
  280.       }
  281.   }
  282. }
  283.  
  284. void sort_best_hits(db)
  285.      database * db;
  286. {
  287.   /* returns nothing.
  288.    * side effects best_hits and document_score_array
  289.    */
  290.  
  291.   long i, doc;
  292.   double worst_weight_to_make_it = 0.0;
  293.   document_table_entry doc_entry;
  294.   long best_hit_number = 0;
  295.  
  296.   /* snuff the scores */
  297.   for(i = 0; i < max_hit_retrieved; i++){
  298.     best_hits_array[i].weight = 0;
  299.   }
  300.  
  301.   /* loop over the doc, and keep the doc_id and weight in best hit table */
  302.   for(doc = 0; doc < db->doc_table_allocated_entries; doc++){
  303.     double weight = document_score_array[doc];
  304.     if(worst_weight_to_make_it < weight){
  305.       /* merge it into the best_hits array. start at the bottom */
  306.       for(i = (max_hit_retrieved - 1); i >= 0; i--){
  307.     if(weight > best_hits_array[i].weight 
  308.        /* && (check_document_id(doc, db) == true) too slow.*/
  309.        ){
  310.       /* move this entry down */    
  311.       if((i + 1) < max_hit_retrieved){
  312.         best_hits_array[i+1].weight = best_hits_array[i].weight;
  313.         best_hits_array[i+1].document_id = best_hits_array[i].document_id;
  314.       }
  315.       best_hits_array[i].document_id = doc;
  316.         best_hits_array[i].weight = weight;
  317.     }
  318.     else
  319.       break;
  320.       }      
  321.     }
  322.   }
  323.   
  324.   for(i = 0; i < max_hit_retrieved; i++){
  325.     if(best_hits_array[i].weight <= 0)  /* if we are out of good stuff, return */
  326.       return;
  327.     /* fill in the rest of the hit */
  328.     if (read_document_table_entry(&doc_entry,
  329.                   best_hits_array[i].document_id,
  330.                   db) 
  331.     == true){
  332.       best_hits_array[best_hit_number].weight = best_hits_array[i].weight;
  333.       best_hits_array[best_hit_number].document_id = best_hits_array[i].document_id;
  334.       best_hits_array[best_hit_number].start_character = doc_entry.start_character;
  335.       best_hits_array[best_hit_number].end_character = doc_entry.end_character;
  336.       best_hits_array[best_hit_number].document_length = doc_entry.document_length;
  337.       best_hits_array[best_hit_number].number_of_lines = doc_entry.number_of_lines;
  338.       read_filename_table_entry(doc_entry.filename_id, 
  339.                 best_hits_array[best_hit_number].filename,
  340.                 best_hits_array[best_hit_number].type,
  341.                 NULL,
  342.                 db),
  343.       strncpy(best_hits_array[best_hit_number].headline, 
  344.           read_headline_table_entry(doc_entry.headline_id,db),
  345.           MAX_FILE_NAME_LEN);
  346.       best_hit_number++;
  347.     } 
  348.     beFriendly();
  349.   }
  350.   for(i = best_hit_number; i < max_hit_retrieved; i++){
  351.     best_hits_array[best_hit_number].weight = 0;
  352.   }
  353.   /* print_best_hits(s);  for debugging */
  354. }
  355.  
  356.  
  357. /* returns the next best hit */
  358. long best_hit(db, doc_id, best_character, best_line, score)
  359.      database *db;
  360.      long *doc_id;    
  361.      long *best_character;
  362.      long *best_line;
  363.      long *score;
  364. {
  365.  
  366.   *best_character = 0; 
  367.   *best_line = 0;
  368.   
  369. #ifdef BOOL
  370.   if (currentQuery != NULL) /* for boolean */
  371.    {
  372.      send(currentQuery,GetBestHit,db,doc_id,best_character,best_line,score);
  373.      if (*doc_id > 0)
  374.        return(0); /* ok */
  375.      else
  376.        return(-1); /* no more docs */
  377.    }
  378. #endif /* BOOL */
  379.  
  380.   if(current_best_hit > best_hits_array_len)
  381.     return(1);
  382.   if(best_hits_array[current_best_hit].weight == 0)
  383.     return(1);
  384.   *doc_id = best_hits_array[current_best_hit].document_id;
  385.   *score  = best_hits_array[current_best_hit].weight;
  386.   current_best_hit++;
  387.   return(0);
  388. }
  389.  
  390. long finished_best_hit(db)
  391. database *db;
  392.  
  393. #ifdef BOOL
  394.   if (currentQuery != NULL) /* for boolean */
  395.    { send(currentQuery,Delete);
  396.      currentQuery = NULL;
  397.      return(0);
  398.    }
  399. #endif /* BOOL */
  400.  
  401.   /* if we are on a small machine, we might want to 
  402.      destroy_document_score_array */
  403.   clear_document_score_array();
  404.   clear_best_hits_array();
  405.   current_best_hit = 0;
  406.   return(0);
  407. }
  408.  
  409. /*=============================*    
  410.  *===  Searching for words  ===*
  411.  *=============================*/
  412.  
  413. /* see irext.h for doc */
  414. long init_search_word (db)
  415.      database* db;
  416. {
  417.   return(0);
  418. }
  419.  
  420. /* see irext.h for doc */
  421. long search_word(word,char_pos, line_pos, weight, doc_id, 
  422.          word_pair, db)
  423.      char *word; /* the word to be searched for */
  424.      long char_pos;        /* the position of the start of the word */
  425.      long line_pos;        /* is this needed? not for signature system */
  426.      long weight;        /* how important the word looks syntactically,
  427.                    such as is it bold */
  428.      long doc_id;        /* current document, seed words is 0,
  429.                    then it increments into the relevant 
  430.                    document */
  431.      long word_pair;
  432.      database *db;
  433. {
  434.   /* this side effects the document_score_array,
  435.    * and downcases the word.
  436.    * Returns 0 if successful or word not present, 
  437.    * returns non-0 if an error.
  438.    *
  439.    */
  440.   
  441.   long not_full_flag = INDEX_BLOCK_FULL_FLAG; /*start out full so it will go on looking */
  442.   long count, index_block_size;
  443.   long internal_document_id, internal_weight, number_of_valid_entries;
  444.   long index_file_block_number;
  445.   long number_of_occurances;
  446.  
  447.   FOUR_BYTE index_buffer_data[INDEX_ELEMENT_SIZE*(1024/4)];
  448.   char *index_buffer;
  449.   char *i;
  450.   FILE *stream = NULL;
  451.  
  452.   index_buffer = (char*)index_buffer_data;
  453.  
  454.   index_file_block_number = 
  455.     look_up_word_in_dictionary(word, &number_of_occurances, db);
  456.  
  457.   current_best_hit = 0;  /* so that the best hits willstart from 0 */
  458.  
  459.   /* check the document_score_array */
  460.   if(document_score_array_len < db->doc_table_allocated_entries)
  461.     make_document_score_array(db->doc_table_allocated_entries);
  462.  
  463.   if(index_file_block_number >= 0){
  464.     stream = db->index_stream;
  465.     
  466.     while((not_full_flag != INDEX_BLOCK_NOT_FULL_FLAG) && 
  467.       (index_file_block_number != 0)){    
  468.       /* read the index block */
  469.       if (0 != fseek(stream, (long)index_file_block_number, 
  470.              SEEK_SET))    
  471.     { 
  472.       waislog(WLOG_HIGH, WLOG_ERROR, 
  473.           "fseek failed into the inverted file to position %ld",
  474.           (long)index_file_block_number); 
  475.       return(-1);
  476.     }
  477.       
  478.       read(fileno(stream),index_buffer,INDEX_BLOCK_HEADER_SIZE);
  479.  
  480.       ASSIGN(not_full_flag,
  481.          INDEX_BLOCK_FLAG_SIZE,
  482.          index_buffer,
  483.          INDEX_BLOCK_HEADER_SIZE,
  484.          0 );
  485.       ASSIGN(index_file_block_number,NEXT_INDEX_BLOCK_SIZE,
  486.          index_buffer+INDEX_BLOCK_FLAG_SIZE,
  487.          INDEX_BLOCK_HEADER_SIZE,
  488.          INDEX_BLOCK_FLAG_SIZE);
  489.       ASSIGN(index_block_size,INDEX_BLOCK_SIZE_SIZE,
  490.          index_buffer+INDEX_BLOCK_FLAG_SIZE+NEXT_INDEX_BLOCK_SIZE,
  491.          INDEX_BLOCK_HEADER_SIZE,
  492.          INDEX_BLOCK_FLAG_SIZE+NEXT_INDEX_BLOCK_SIZE);
  493.  
  494. /* 
  495.   this is equivalent, but slower:
  496.       not_full_flag = read_bytes(INDEX_BLOCK_FLAG_SIZE, stream);
  497.       index_file_block_number = read_bytes(NEXT_INDEX_BLOCK_SIZE, stream);
  498.       index_block_size = read_bytes(INDEX_BLOCK_SIZE_SIZE, stream);
  499.  
  500.       printf("flag = %d, block_num = %d, block_size = %d\n",
  501.          not_full_flag, 
  502.          index_file_block_number,
  503.          index_block_size);
  504.  
  505.       fflush(stdout);
  506. */
  507.       if(EOF == index_block_size) 
  508.     { 
  509.       waislog(WLOG_HIGH, WLOG_ERROR, 
  510.           "reading from the index file failed");
  511.       return(-1);
  512.     }
  513.       
  514.       if(not_full_flag == INDEX_BLOCK_NOT_FULL_FLAG){
  515.     /* not full */
  516.     number_of_valid_entries = index_file_block_number;
  517.       }
  518.       else if(not_full_flag == INDEX_BLOCK_FULL_FLAG){
  519.     /* full */
  520.     number_of_valid_entries = index_block_size - INDEX_BLOCK_HEADER_SIZE;
  521.       }
  522.       else{            /* bad news, file is corrupted. */
  523.     waislog(WLOG_HIGH, WLOG_ERROR, 
  524.         "Expected the flag in the inverted file to be valid.  it is %ld",
  525.         not_full_flag);
  526.     return(-1);
  527.       }
  528.       /* printf("number of valid bytes: %ld\n", number_of_valid_entries); */
  529.       
  530.       /* add the array to the document_score_array */
  531.       number_of_valid_entries /= INDEX_ELEMENT_SIZE;
  532.  
  533.       for(count=0;count <  number_of_valid_entries;count++) {
  534.     int wgt;
  535.     int did;
  536.     if(count%1024 == 0) {
  537.       read(fileno(stream),index_buffer,INDEX_ELEMENT_SIZE*
  538.         MIN(1024,number_of_valid_entries-count));
  539.       i=index_buffer;
  540.     }
  541.     ASSIGN(wgt,WEIGHT_SIZE,    
  542.            i+DOCUMENT_ID_SIZE+WORD_POSITION_SIZE+CHARACTER_POSITION_SIZE,
  543.            INDEX_ELEMENT_SIZE,
  544.            DOCUMENT_ID_SIZE+WORD_POSITION_SIZE+CHARACTER_POSITION_SIZE);
  545.     ASSIGN(did,DOCUMENT_ID_SIZE,i,INDEX_ELEMENT_SIZE,0);
  546.  
  547.     internal_weight = wgt;
  548.     internal_document_id = did;
  549.  
  550.     /*
  551.     printf("entry %ld, Doc_id: %ld, weight %ld \n",
  552.         count, internal_document_id, internal_weight);
  553.     fflush(stdout);
  554.     */
  555.     if(EOF == internal_weight) 
  556.       { 
  557.         waislog(WLOG_HIGH, WLOG_ERROR, 
  558.             "reading from the doc-id table failed");
  559.         return(-1);
  560.       }
  561.     /* if(doc_id > 0) we are doing a relevant document */
  562.     document_score_array[internal_document_id] += 
  563.       (doc_id) ? (internal_weight * RF_WEIGHTING) : internal_weight;
  564.     i+=INDEX_ELEMENT_SIZE;
  565.       }
  566.     }
  567.     return(0); 
  568.   }
  569.   else if(0 == index_file_block_number){
  570.     /* an error occurred on looking up the word */
  571.     return(-1);
  572.   }
  573.   else                /* index_file_block_number is negative */
  574.     return(0);        /* word not present */
  575. }
  576.  
  577. /* now collect the best hits */
  578. long finished_search_word(db)
  579.      database *db;
  580.  
  581. #ifdef BOOL
  582.   if (currentQuery != NULL)
  583.     return; /* do nothing for boolean */
  584. #endif /* def BOOL */
  585.  
  586.   /* check the document_score_array */
  587.   if(document_score_array_len < db->doc_table_allocated_entries)
  588.     make_document_score_array(db->doc_table_allocated_entries);
  589.  
  590.   make_best_hits_array(max_hit_retrieved);
  591.   sort_best_hits(db);
  592.   return(0);
  593. }
  594.  
  595.